package com.egao.common.component.elasticsearch.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.CreditCodeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.poi.word.WordUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.egao.common.component.elasticsearch.entity.*;
import com.egao.common.component.elasticsearch.entity.vo.StudentPushMsgVO;
import com.egao.common.component.elasticsearch.listener.ElasticSearchDeleteListener;
import com.egao.common.core.web.JsonResult;
import com.egao.common.core.web.PageParam;
import com.egao.common.core.web.PageResult;
import com.egao.common.module.cms.entity.Article;
import com.egao.common.module.cms.entity.Official;
import com.egao.common.module.cms.mapper.ArticleMapper;
import com.egao.common.module.cms.mapper.OfficialMapper;
import com.egao.common.module.company.constants.CheckRecordConstants;
import com.egao.common.module.company.entity.*;
import com.egao.common.module.company.mapper.MutualMapper;
import com.egao.common.module.company.mapper.PreachCloudMapper;
import com.egao.common.module.company.mapper.PreachMapper;
import com.egao.common.module.company.mapper.RecruitMapper;
import com.egao.common.module.company.service.CompanyService;
import com.egao.common.module.company.service.PositionService;
import com.egao.common.module.company.service.RecruitService;
import com.egao.common.module.push.constants.PushConstants;
import com.egao.common.module.push.entity.PushMsg;
import com.egao.common.module.push.mapper.PushMsgMapper;
import com.egao.common.module.student.entity.Student;
import com.egao.common.module.student.entity.vo.StudentFormVO;
import com.egao.common.module.student.mapper.StudentMapper;
import com.egao.common.module.system.constants.DictConstants;
import com.egao.common.module.system.entity.Dict;
import com.egao.common.module.system.service.CollegeService;
import com.egao.common.module.system.service.DictService;
import com.egao.common.publicly.entity.PubliclyCareerVO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * ElasticSearch 服务
 *
 * @author lym
 */
@Slf4j
@Service
public class ElasticSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private RecruitMapper recruitMapper;

    @Autowired
    private PreachMapper preachMapper;

    @Autowired
    private PreachCloudMapper preachCloudMapper;

    @Autowired
    private MutualMapper mutualMapper;

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private OfficialMapper officialMapper;

    @Autowired
    private PushMsgMapper pushMsgMapper;

    @Autowired
    private CompanyService companyService;

    @Autowired
    private PositionService positionService;

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private DictService dictService;

    private Logger logger = LoggerFactory.getLogger(ElasticSearchService.class.getName());

    /**
     * 搜索
     *
     * @param category 信息类型
     * @param keyword  关键词
     * @param page     当前页数
     * @param limit    每页条数
     * @return ElasticSearchResult
     * @throws Exception
     */
    public ElasticSearchResult search(String category, String keyword, String type, int page, int limit) throws IOException {
        // 关键词为空返回空结果
        if (StrUtil.isBlank(keyword)) {
            return new ElasticSearchResult("请输入关键词");
        }

        page = page <= 0 ? 0 : page;

        // 搜索的索引
        SearchRequest index = new SearchRequest(ElasticSearchConstants.INDEX_NAME_INFORMATION);

        // 构建搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 构建高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.field("content");
        highlightBuilder.field("major");
        highlightBuilder.field("education");
        highlightBuilder.field("positionNames");
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.preTags("<em>");
        highlightBuilder.postTags("</em>");
        searchSourceBuilder.highlighter(highlightBuilder);

        // 构建分页
        searchSourceBuilder.from(page);
        // 设置为true就会返回真实的命中条数
        searchSourceBuilder.trackTotalHits(true);
        searchSourceBuilder.size(limit).sort(new FieldSortBuilder("createTime").order(SortOrder.DESC));

        // 复合查询 should或者 must并且
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        // 信息类型相等 term 完全匹配
        if (!StrUtil.isBlank(category)) {
            boolQueryBuilder.must(QueryBuilders.termQuery(ElasticSearchConstants.SEARCH_TYPE, category));
        }

        if (!StrUtil.isBlank(type)) {
            boolQueryBuilder.must(QueryBuilders.termQuery("type.keyword", type));
        }

        // 模糊查询标题 match 高层查询(具备模糊查询效果)
        if (!StrUtil.isBlank(keyword)) {
            QueryBuilder query = QueryBuilders.boolQuery()
                    .should(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.wildcardQuery("title.keyword", "*" + keyword + "*")))
                    .should(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.matchPhraseQuery("major", keyword)))
                    .should(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.matchPhraseQuery("education", keyword)))
                    .should(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.matchPhraseQuery("content", keyword)))
                    .should(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.matchPhraseQuery("positionNames", keyword)));
            boolQueryBuilder.must(query);

        }

        searchSourceBuilder.query(boolQueryBuilder);

        // source builder 10秒timeout
        searchSourceBuilder.timeout(new TimeValue(10, TimeUnit.SECONDS));
        index.source(searchSourceBuilder);

        // 请求查询得到返回响应
        SearchResponse searchResponse = restHighLevelClient.search(index, RequestOptions.DEFAULT);

        // 封装结果
        List<Map<String, Object>> dataList = new ArrayList<>();

        for (SearchHit hit : searchResponse.getHits().getHits()) {

            // 文档属性
            Map<String, Object> fields = hit.getSourceAsMap();

            // 文档高亮属性
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();

            if (highlightFields != null && highlightFields.size() > 0) {
                // 高亮文档结果
                for (String key : highlightFields.keySet()) {
                    fields.remove(key);
                    fields.put(key, highlightField(highlightFields, key));
                }
            }
            if (fields.get("createTime") != null) {
                long timeCreated = (long) fields.get("createTime");
                fields.put("createTime", DateUtil.format(new Date(timeCreated), "yyyy-MM-dd HH:mm"));
            }
            if (fields.get("content") != null) {
                String content = (String) fields.get("content");
                if (content.indexOf("<em>") < 0) {
                    fields.put("content", "");
                }
            }

            dataList.add(fields);
        }

        // 数据条数
        long total = searchResponse.getHits().getTotalHits().value;

        // 返回结果
        return new ElasticSearchResult(category, keyword, page, limit, (int) total, dataList);
    }

    /**
     * 查询学生接收推送匹配信息
     *
     * @param id    学生ID
     * @param page  当前页
     * @param limit 每页多少条
     */
    public PageResult<StudentPushMsgVO> searchStudentPushMsg(String id, int page, int limit) throws IOException {
        page = page <= 1 ? 1 : page;

        // 搜索的索引
        SearchRequest index = new SearchRequest(ElasticSearchConstants.INDEX_NAME_PUSH_MSG);

        // 构建搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();


        // 设置为true就会返回真实的命中条数
        searchSourceBuilder.trackTotalHits(true);
        // 构建分页
        //searchSourceBuilder.from(page);
        searchSourceBuilder.size(3000);
        // 构建排序
        searchSourceBuilder.sort(new FieldSortBuilder("pushDate").order(SortOrder.DESC));

        // 复合查询 should或者 must并且
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        // 单位同意推送
        boolQueryBuilder.must(QueryBuilders.termQuery("companyFlag", PushConstants.YES));
        // 学校同意
        boolQueryBuilder.must(QueryBuilders.termQuery("adminFlag", PushConstants.YES));

        boolQueryBuilder.must(QueryBuilders.termQuery("studentId", id));

        searchSourceBuilder.query(boolQueryBuilder);

        // source builder 10秒timeout
        searchSourceBuilder.timeout(new TimeValue(10, TimeUnit.SECONDS));
        index.source(searchSourceBuilder);

        // 请求查询得到返回响应
        SearchResponse searchResponse = restHighLevelClient.search(index, RequestOptions.DEFAULT);

        // 数据条数
        long total = searchResponse.getHits().getTotalHits().value;

        int pageIndex = 0;
        String xh = "";
        List<Integer> companyIds = new ArrayList<>();
        Map<Object, Object> dictMaps = dictService.getCacheDictMaps();
        List<StudentPushMsgVO> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {

            int start = (page - 1) * limit;
            if (pageIndex < start) {
                pageIndex++;
                continue;
            }
            if (pageIndex == start + limit) {
                break;
            }

            Map<String, Object> fields = hit.getSourceAsMap();

            StudentPushMsgVO item = new StudentPushMsgVO();

            item.setType(fields.get("type") != null ? fields.get("type").toString() : "");

            xh = fields.get("xh") != null ? fields.get("xh").toString() : "";
            item.setXh(xh);
            item.setXm("");
            item.setMajorName(fields.get("majorName") != null ? fields.get("majorName").toString() : "");

            Integer companyId = fields.get("companyId") != null ? (Integer) fields.get("companyId") : null;
            item.setCompanyId(companyId);
            item.setCompanyName("");
            item.setCompanyUrl("/home/companydetail?id=" + companyId);
            companyIds.add(companyId);

            String nature = fields.get("nature") != null ? fields.get("nature").toString() : "";
            if (!StrUtil.isBlank(nature)) {
                item.setCompanyNature(dictService.cacheLabel(DictConstants.COMPANY_NATURE, nature, dictMaps));
            }

            String industry = fields.get("industry") != null ? fields.get("industry").toString() : "";
            if (!StrUtil.isBlank(industry)) {
                item.setCompanyIndustry(dictService.cacheLabel(DictConstants.COMPANY_INDUSTRY, industry, dictMaps));
            }

            String scale = fields.get("scale") != null ? fields.get("scale").toString() : "";
            if (!StrUtil.isBlank(scale)) {
                item.setCompanyScale(dictService.cacheLabel(DictConstants.COMPANY_SCALE, scale, dictMaps));
            }

            String province = fields.get("province") != null ? fields.get("province").toString() : "";
            String city = fields.get("city") != null ? fields.get("city").toString() : "";
            item.setProvinceCity(province + city);

            item.setBusinessId(fields.get("businessId") != null ? fields.get("businessId").toString() : "");
            item.setTitle(fields.get("title") != null ? fields.get("title").toString() : "");

            item.setReadFlag(fields.get("readFlag") != null ? fields.get("readFlag").toString() : "");
            item.setResumeFlag(fields.get("resumeFlag") != null ? fields.get("resumeFlag").toString() : "");

            long pushDateL = fields.get("pushDate") != null ? (Long) fields.get("pushDate") : 0L;
            if (pushDateL != 0L) {
                item.setPushDate(DateUtil.date(pushDateL));
            }

            String positionResult = "";
            String positionMatching = fields.get("positionMatching") != null ? fields.get("positionMatching").toString() : "";
            String positionNames = fields.get("positionNames") != null ? fields.get("positionNames").toString() : "";
            if (!StrUtil.isBlank(positionMatching) && !StrUtil.isBlank(positionNames)) {
                String[] pms = positionMatching.split("\\|");
                String[] pns = positionNames.split(",");
                if (pms.length == pns.length) {
                    for (int i = 0; i < pms.length; i++) {
                        String[] matching = pms[i].split(",");
                        positionResult += i + 1 + "." + pns[i] + "[" + matching[1] + "]";
                        positionResult += "<br>";
                    }
                } else {
                    String[] matching = pms[0].split(",");
                    positionResult = "1." + pns[0] + "[" + matching[1] + "]";
                }
            }
            item.setPositionResult(positionResult);

            String businessUrl = "";
            switch (item.getType()) {
                case "1":
                    businessUrl = "/home/career/internship?id=" + item.getBusinessId();
                    break;
                case "2":
                    businessUrl = "/home/career/preachmore?id=" + item.getBusinessId();
                    break;
                case "3":
                    businessUrl = "/home/career/cloudmore?id=" + item.getBusinessId();
                    break;
            }
            item.setBusinessUrl(businessUrl);

            list.add(item);
            pageIndex++;
        }

        if (list.size() == 0) {
            return new PageResult<>(list, total);
        }

        List<Company> companyList = companyService.list(new QueryWrapper<Company>().in("id", companyIds));
        Student student = studentMapper.selectOne(new QueryWrapper<Student>().eq("xh", xh).last("limit 1"));
        String xm = student != null ? student.getXm() : "";
        for (StudentPushMsgVO item : list) {
            item.setXm(xm);
            for (Company company : companyList) {
                if (item.getCompanyId().equals(company.getId())) {
                    item.setCompanyName(company.getName());
                    break;
                }
            }
        }

        return new PageResult<>(list, total);
    }

    /**
     * 添加内容到索引
     *
     * @param index             索引名称
     * @param elasticSearchData 添加内容
     */
    public void add(String index, ElasticSearchData elasticSearchData) {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout(ElasticSearchConstants.TIME_OUT);

        bulkRequest.add(
                new IndexRequest(index)
                        .id(elasticSearchData.getCategory() + "-" + elasticSearchData.getId())
                        .source(JSON.toJSONString(elasticSearchData), XContentType.JSON)
        );

        try {

            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

            if (bulkResponse.hasFailures()) {
                logger.error("ElasticSearchService Add Failure：" + bulkResponse.buildFailureMessage());
            }
        } catch (IOException e) {
            logger.error("ElasticSearchService Add ERROR", e);
        }
    }

    /**
     * 添加内容到推送索引
     *
     * @param index              索引名称
     * @param elasticPushMsgData 添加内容
     */
    public void add(String index, ElasticPushMsgData elasticPushMsgData) {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout(ElasticSearchConstants.TIME_OUT);

        bulkRequest.add(
                new IndexRequest(index)
                        .id(elasticPushMsgData.getId())
                        .source(JSON.toJSONString(elasticPushMsgData), XContentType.JSON)
        );

        try {
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

            if (bulkResponse.hasFailures()) {
                logger.error("ElasticSearchService Add Failure：" + bulkResponse.buildFailureMessage());
            }
        } catch (IOException e) {
            logger.error("ElasticSearchService Add ERROR", e);
        }
    }

    /**
     * 添加内容到推送索引
     *
     * @param index                  索引名称
     * @param elasticPushMsgDataList 多条数据
     */
    public void add(String index, List<ElasticPushMsgData> elasticPushMsgDataList) {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout(ElasticSearchConstants.TIME_OUT);

        for (ElasticPushMsgData elasticPushMsgData : elasticPushMsgDataList) {
            bulkRequest.add(
                    new IndexRequest(index)
                            .id(elasticPushMsgData.getId())
                            .source(JSON.toJSONString(elasticPushMsgData), XContentType.JSON)
            );
        }

        try {
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

            if (bulkResponse.hasFailures()) {
                logger.error("ElasticSearchService Add Failure：" + bulkResponse.buildFailureMessage());
            }
        } catch (IOException e) {
            logger.error("ElasticSearchService Add ERROR", e);
        }
    }

    /**
     * 添加内容到推送索引
     *
     * @param elasticSearchDataList 多条数据
     */
    public void add(List<ElasticSearchData> elasticSearchDataList) {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout(ElasticSearchConstants.TIME_OUT);

        for (ElasticSearchData elasticSearchData : elasticSearchDataList) {
            bulkRequest.add(
                    new IndexRequest(ElasticSearchConstants.INDEX_NAME_INFORMATION)
                            .id(elasticSearchData.getCategory() + "-" + elasticSearchData.getId())
                            .source(JSON.toJSONString(elasticSearchData), XContentType.JSON)
            );
        }

        try {
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

            if (bulkResponse.hasFailures()) {
                logger.error("ElasticSearchService Add Failure：" + bulkResponse.buildFailureMessage());
            }
        } catch (IOException e) {
            logger.error("ElasticSearchService Add ERROR", e);
        }
    }


    /**
     * 保存招聘信息到es
     *
     * @param recruit 招聘信息对象
     */
    public void save(Recruit recruit) {
        add(ElasticSearchConstants.INDEX_NAME_INFORMATION, copyRecruit(recruit));
    }

    /**
     * 保存多条招聘信息到es
     *
     * @param recruits 招聘信息对象
     */
    public void saveRecruitList(List<Recruit> recruits) {
        List<ElasticSearchData> dataList = new ArrayList<>();
        for (Recruit recruit : recruits) {
            dataList.add(copyRecruit(recruit));
        }
        add(dataList);
    }

    /**
     * 复制招聘信息
     *
     * @param recruit 招聘
     * @return
     */
    private ElasticSearchData copyRecruit(Recruit recruit) {
        ElasticSearchData data = new ElasticSearchData();
        data.setType(ElasticSearchConstants.INFORMATION_SCHOOL_RECRUIT);
        data.setCategory(ElasticSearchConstants.INFORMATION_RECRUIT);
        data.setSubcategory(recruit.getType());
        data.setId(recruit.getId().toString());
        data.setTitle(recruit.getTitle());
        data.setUrl(ElasticSearchConstants.getCategoryUrl(ElasticSearchConstants.INFORMATION_RECRUIT, recruit.getType()) + "?id=" + recruit.getId());
        data.setMajor(recruit.getMajors());
        data.setEducation(recruit.getEducation());
        data.setCreateTime(recruit.getCreateTime());
        data.setContent(HtmlUtil.cleanHtmlTag(recruit.getContent()));
        data.setNumber(recruit.getNumber());
        data.setPositionNames(recruit.getPositionNames());
        return data;
    }

    /**
     * 保存文章信息到es
     *
     * @param article 文章信息对象
     */
    public void save(Article article) {
        add(ElasticSearchConstants.INDEX_NAME_INFORMATION, copyArticle(article));
    }

    /**
     * 保存多条文章信息到es
     *
     * @param articles 文章信息对象
     */
    public void saveArticleList(List<Article> articles) {
        List<ElasticSearchData> dataList = new ArrayList<>();
        for (Article article : articles) {
            dataList.add(copyArticle(article));
        }
        add(dataList);
    }

    private ElasticSearchData copyArticle(Article article) {
        ElasticSearchData data = new ElasticSearchData();
        data.setType(ElasticSearchConstants.INFORMATION_NEWS);
        data.setCategory(ElasticSearchConstants.INFORMATION_ARTICLE);
        data.setSubcategory(article.getCategoryName());
        data.setId(article.getId().toString());
        data.setTitle(article.getTitle());
        data.setUrl(ElasticSearchConstants.getCategoryUrl(ElasticSearchConstants.INFORMATION_ARTICLE, null) + "?id=" + article.getId());
        data.setCreateTime(article.getCreateTime());
        data.setContent(article.getContent() == null ? null : HtmlUtil.cleanHtmlTag(article.getContent()));
        return data;
    }

    /**
     * 保存公务员信息到es
     *
     * @param official 公务员信息对象
     */
    public void save(Official official) {
        add(ElasticSearchConstants.INDEX_NAME_INFORMATION, copyOfficial(official));
    }

    /**
     * 保存多条公务员信息到es
     *
     * @param officials 公务员信息对象
     */
    public void saveOfficialList(List<Official> officials) {
        List<ElasticSearchData> dataList = new ArrayList<>();
        for (Official official : officials) {
            dataList.add(copyOfficial(official));
        }
        add(dataList);
    }

    private ElasticSearchData copyOfficial(Official official) {
        ElasticSearchData data = new ElasticSearchData();
        data.setType(ElasticSearchConstants.INFORMATION_SERVANT);
        data.setCategory(ElasticSearchConstants.INFORMATION_OFFICIAL);
        data.setId(official.getId().toString());
        data.setTitle(official.getTitle());
        data.setUrl(ElasticSearchConstants.getCategoryUrl(ElasticSearchConstants.INFORMATION_OFFICIAL, null) + "?id=" + official.getId());
        data.setCreateTime(official.getCreateTime());
        data.setContent(official.getContent() == null ? null : HtmlUtil.cleanHtmlTag(official.getContent()));
        return data;
    }

    /**
     * 保存推送信息到es
     *
     * @param pushMsg 招聘信息对象
     */
    public void save(PushMsg pushMsg) {
        ElasticPushMsgData data = new ElasticPushMsgData();
        BeanUtil.copyProperties(pushMsg, data);
        data.setId(pushMsg.getId() + "");
        add(ElasticSearchConstants.INDEX_NAME_PUSH_MSG, data);
    }

    /**
     * 保存推送信息到es
     *
     * @param pushMsgList 推送信息对象
     */
    public void save(List<PushMsg> pushMsgList) {
        List<StudentFormVO> studentFormVOList = studentMapper.getAllStudent();
        List<Company> companyList = companyService.list();
        List<Position> positionList = positionService.list();
        save(pushMsgList, studentFormVOList, companyList, positionList);
    }

    /**
     * 保存推送信息到es
     *
     * @param pushMsgList 推送信息对象
     * @param id          业务编号
     * @param type        业务类型
     */
    public void savePushList(List<PushMsg> pushMsgList, Integer id, String type) {
        Company company = null;
        String positionNames = null;
        String ids = null;
        List<Position> positionList = null;
        if (CheckRecordConstants.CHECK_RECRUIT.equals(type)) {
            Recruit recruit = recruitMapper.selectById(id);
            company = companyService.getById(recruit.getCompanyId());
            positionNames = recruit.getPositionNames();
            ids = recruit.getPositionIds();
        }
        if (CheckRecordConstants.CHECK_PREACH.equals(type)) {
            Preach preach = preachMapper.selectById(id);
            company = companyService.getById(preach.getCompanyId());
            positionNames = preach.getPositionNames();
            ids = preach.getPositionIds();
        }
        if (CheckRecordConstants.CHECK_PREACH_CLOUD.equals(type)) {
            PreachCloud preachCloud = preachCloudMapper.selectById(id);
            company = companyService.getById(preachCloud.getCompanyId());
            positionNames = preachCloud.getPositionNames();
            ids = preachCloud.getPositionIds();
        }
        if (ids != null) {
            String[] idArray = ids.split(",");
            List<Integer> idList = new ArrayList<>();
            for (String pId : idArray) {
                idList.add(Integer.parseInt(pId));
            }
            positionList = positionService.list(new QueryWrapper<Position>().in("id", idList));
        }
        List<StudentFormVO> studentFormVOList = studentMapper.getAllStudent();
        List<ElasticPushMsgData> dataList = new ArrayList<>();
        for (PushMsg pushMsg : pushMsgList) {
            ElasticPushMsgData data = new ElasticPushMsgData();
            BeanUtil.copyProperties(pushMsg, data);
            StudentFormVO studentFormVO = getStudent(studentFormVOList, pushMsg.getStudentId());
            data.setCollegeCode(studentFormVO != null ? studentFormVO.getCollegeCode() : "");
            data.setCollegeName(studentFormVO != null ? studentFormVO.getCollegeName() : "");
            data.setMajorName(studentFormVO != null ? studentFormVO.getMajorName() : "");
            data.setYearId(studentFormVO != null ? studentFormVO.getYearId() : 0);
            data.setMatching(pushMsg.getMatching());
            data.setProvince(company == null ? "" : company.getProvince());
            data.setCity(company == null ? "" : company.getCity());
            data.setNature(company == null ? "" : company.getNature());
            data.setIndustry(company == null ? "" : company.getIndustry());
            data.setScale(company == null ? "" : company.getScale());
            data.setId(String.valueOf(pushMsg.getId()));
            String positionMatching = pushMsg.getPositionMatching();
            data.setPositionMatching(positionMatching);

            if (positionNames != null) {
                data.setPositionNames(positionNames);
            }
            if (positionList != null && positionList.size() > 0) {
                ElasticPositionData[] positionData = convertToData(positionList);
                data.setPositions(positionData);
            }
            dataList.add(data);
        }
        add(ElasticSearchConstants.INDEX_NAME_PUSH_MSG, dataList);
    }

    /**
     * 职位对象转换为索引数组保存
     *
     * @param positionList
     * @return
     */
    private ElasticPositionData[] convertToData(List<Position> positionList) {
        int len = positionList.size();
        if (len > 0) {
            ElasticPositionData[] positionData = new ElasticPositionData[len];
            for (int i = 0; i < len; i++) {
                positionData[i] = new ElasticPositionData();
                positionData[i].setId(positionList.get(i).getId());
                positionData[i].setPId("p-" + positionList.get(i).getId());
                positionData[i].setName(positionList.get(i).getName());
                positionData[i].setNumber(getPositionNumber(positionList.get(i).getNumber()));
            }
            return positionData;
        }
        return null;
    }

    /**
     * 获取职位人数，老数据有问题直接为0
     *
     * @param number 职位招聘人数
     * @return
     */
    private long getPositionNumber(String number) {
        try {
            return Long.valueOf(number);
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 保存招聘信息到es
     *
     * @param pushMsgList 推送信息对象
     */
    public void save(List<PushMsg> pushMsgList, List<StudentFormVO> studentList, List<Company> companyList, List<Position> positionList) {
        List<ElasticPushMsgData> dataList = new ArrayList<>();
        for (PushMsg pushMsg : pushMsgList) {
            ElasticPushMsgData data = new ElasticPushMsgData();
            BeanUtil.copyProperties(pushMsg, data);
            StudentFormVO studentFormVO = getStudent(studentList, pushMsg.getStudentId());
            data.setCollegeCode(studentFormVO != null ? studentFormVO.getCollegeCode() : "");
            data.setCollegeName(studentFormVO != null ? studentFormVO.getCollegeName() : "");
            data.setYearId(studentFormVO != null ? studentFormVO.getYearId() : 0);
            data.setMajorName(studentFormVO != null ? studentFormVO.getMajorName() : "");
            data.setMatching(pushMsg.getMatching());
            Company company = getCompany(companyList, pushMsg.getCompanyId());
            data.setProvince(company != null ? company.getProvince() : "");
            data.setCity(company != null ? company.getCity() : "");
            data.setNature(company != null ? company.getNature() : "");
            data.setIndustry(company != null ? company.getIndustry() : "");
            data.setScale(company != null ? company.getScale() : "");
            data.setId(String.valueOf(pushMsg.getId()));

            String positionMatching = pushMsg.getPositionMatching();
            data.setPositionMatching(positionMatching);
            if (positionMatching != null) {
                String[] pos = positionMatching.split("\\|");
                if (pos.length > 0) {
                    StringBuilder sr = new StringBuilder();
                    String[] positionName = new String[pos.length];
                    List<Position> positions = new ArrayList<>();
                    for (int i = 0; i < pos.length; i++) {
                        int end = pos[i].indexOf(",");
                        if (end > 0) {
                            String pId = pos[i].substring(0, end);
                            Position position = getPosition(positionList, Integer.parseInt(pId));
                            if (position != null) {
                                positions.add(position);
                                positionName[i] = position.getName();
                                sr.append(positionName[i]).append(",");
                            } else {
                                positionName[i] = "";
                            }
                        }
                    }
                    data.setPositions(convertToData(positions));
                    data.setPositionNames(sr.deleteCharAt(sr.lastIndexOf(",")).toString());
                }
            }
            dataList.add(data);
        }
        add(ElasticSearchConstants.INDEX_NAME_PUSH_MSG, dataList);
    }

    /**
     * 找单位
     *
     * @param companyList
     * @return
     */
    private Company getCompany(List<Company> companyList, Integer companyId) {
        if (companyId == null) {
            return null;
        }
        for (Company company : companyList) {
            if (companyId.equals(company.getId())) {
                return company;
            }
        }
        return null;
    }

    /**
     * 找职位
     *
     * @param positionList
     * @return
     */
    private Position getPosition(List<Position> positionList, Integer positionId) {
        if (positionId == null) {
            return null;
        }
        for (Position position : positionList) {
            if (positionId.equals(position.getId())) {
                return position;
            }
        }
        return null;
    }

    private StudentFormVO getStudent(List<StudentFormVO> studentList, Integer studentId) {
        if (studentId == null) {
            return null;
        }
        for (StudentFormVO student : studentList) {
            if (studentId.equals(student.getId())) {
                return student;
            }
        }
        return null;
    }

    /**
     * 保存宣讲会信息到es
     *
     * @param preach 宣讲会信息对象
     */
    public void save(Preach preach) {
        add(ElasticSearchConstants.INDEX_NAME_INFORMATION, copyPreach(preach));
    }

    /**
     * 保存宣讲会信息到es
     *
     * @param preachList 宣讲会信息对象
     */
    public void savePreachList(List<Preach> preachList) {
        List<ElasticSearchData> dataList = new ArrayList<>();
        for (Preach preach : preachList) {
            dataList.add(copyPreach(preach));
        }
        add(dataList);
    }

    private ElasticSearchData copyPreach(Preach preach) {
        ElasticSearchData data = new ElasticSearchData();
        data.setType(ElasticSearchConstants.INFORMATION_SCHOOL_RECRUIT);
        data.setCategory(ElasticSearchConstants.INFORMATION_PREACH);
        data.setId(preach.getId().toString());
        data.setTitle(preach.getTitle());
        data.setUrl(ElasticSearchConstants.getCategoryUrl(ElasticSearchConstants.INFORMATION_PREACH, null) + "?id=" + preach.getId());
        data.setMajor(preach.getMajors());
        data.setEducation(preach.getEducation());
        data.setCreateTime(preach.getHoldTime());
        data.setPositionNames(preach.getPositionNames());
        data.setAddress(preach.getHoldAddress());
        data.setContent(HtmlUtil.cleanHtmlTag(preach.getContent()));
        data.setCompanyName(preach.getCompanyName());
        data.setPositionNames(preach.getPositionNames());
        return data;
    }

    /**
     * 保存空中宣讲会信息到es
     *
     * @param preachCloud 空中宣讲会信息对象
     */
    public void save(PreachCloud preachCloud) {
        add(ElasticSearchConstants.INDEX_NAME_INFORMATION, copyPreachCloud(preachCloud));
    }

    /**
     * 保存空中宣讲会信息到es
     *
     * @param preachClouds 空中宣讲会信息对象
     */
    public void savePreachCloudList(List<PreachCloud> preachClouds) {
        List<ElasticSearchData> dataList = new ArrayList<>();
        for (PreachCloud preachCloud : preachClouds) {
            dataList.add(copyPreachCloud(preachCloud));
        }
        add(dataList);
    }

    private ElasticSearchData copyPreachCloud(PreachCloud preachCloud) {
        ElasticSearchData data = new ElasticSearchData();
        data.setCategory(ElasticSearchConstants.INFORMATION_PREACH_CLOUD);
        data.setType(ElasticSearchConstants.INFORMATION_SCHOOL_RECRUIT);
        data.setId(preachCloud.getId().toString());
        data.setTitle(preachCloud.getTitle());
        data.setUrl(ElasticSearchConstants.getCategoryUrl(ElasticSearchConstants.INFORMATION_PREACH_CLOUD, null) + "?id=" + preachCloud.getId());
        data.setMajor(preachCloud.getMajors());
        data.setEducation(preachCloud.getEducation());
        data.setCreateTime(preachCloud.getHoldTime());
        data.setPositionNames(preachCloud.getPositionNames());
        data.setAddress(preachCloud.getHoldAddress());
        data.setContent(HtmlUtil.cleanHtmlTag(preachCloud.getContent()));
        return data;
    }

    /**
     * 保存校内双选会信息到es
     *
     * @param mutual 校内双选会信息对象
     */
    public void save(Mutual mutual) {
        add(ElasticSearchConstants.INDEX_NAME_INFORMATION, copyMutual(mutual));
    }

    /**
     * 保存校内双选会信息到es
     *
     * @param mutuals 校内双选会信息对象
     */
    public void saveMutualList(List<Mutual> mutuals) {
        List<ElasticSearchData> dataList = new ArrayList<>();
        for (Mutual mutual : mutuals) {
            dataList.add(copyMutual(mutual));
        }
        add(dataList);
    }

    private ElasticSearchData copyMutual(Mutual mutual) {
        ElasticSearchData data = new ElasticSearchData();
        data.setCategory(ElasticSearchConstants.INFORMATION_MUTUAL);
        data.setType(ElasticSearchConstants.INFORMATION_SCHOOL_RECRUIT);
        data.setId(mutual.getId().toString());
        data.setTitle(mutual.getTitle());
        data.setUrl(ElasticSearchConstants.getCategoryUrl(ElasticSearchConstants.INFORMATION_MUTUAL, null) + "?id=" + mutual.getId());
        data.setCreateTime(mutual.getStartTime());
        data.setAddress(mutual.getFieldName());
        data.setCompanyName(mutual.getCompanyName());
        data.setContent(HtmlUtil.cleanHtmlTag(mutual.getContent()));
        return data;
    }

    /**
     * 异步删除文档
     *
     * @param index 索引名称
     * @param id    文档ID
     */
    public void delete(String index, String id) {
        DeleteRequest deleteRequest = new DeleteRequest(index, id);
        deleteRequest.timeout(ElasticSearchConstants.TIME_OUT);
        restHighLevelClient.deleteAsync(deleteRequest, RequestOptions.DEFAULT, new ElasticSearchDeleteListener());
    }

    /**
     * 异步删除文档
     *
     * @param category 文档类型
     */
    public void delete(String category) {
        DeleteByQueryRequest request = new DeleteByQueryRequest(ElasticSearchConstants.INDEX_NAME_INFORMATION);
        request.setQuery(new TermsQueryBuilder("category", category));
        // 批次大小
        request.setBatchSize(1000);
        // 并行
        request.setSlices(2);
        // 使用滚动参数来控制“搜索上下文”存活的时间
        request.setScroll(TimeValue.timeValueMinutes(10));
        // 超时
        request.setTimeout(TimeValue.timeValueMinutes(2));
        // 刷新索引
        request.setRefresh(true);
        try {
            BulkByScrollResponse response = restHighLevelClient.deleteByQuery(request, RequestOptions.DEFAULT);
            log.info("delete index result : {}", response.getStatus().getUpdated());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean isExistData(String category) throws IOException {
        // 搜索的索引
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstants.INDEX_NAME_INFORMATION);
        // 构建搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 复合查询 should或者 must并且
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.termQuery("category.keyword", category));
        searchSourceBuilder.query(boolQueryBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        if (searchResponse.getHits().getTotalHits().value > 0) {
            return true;
        }
        return false;
    }


    /**
     * 异步删除文档
     *
     * @param lists 文档ID
     */
    public void delete(List<String> lists) {
        BulkRequest request = new BulkRequest();
        for (String id : lists) {
            DeleteRequest deleteRequest = new DeleteRequest(ElasticSearchConstants.INDEX_NAME_INFORMATION, id);
            request.add(deleteRequest);
        }

        try {
            restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 构造普通文本结果
     *
     * @param fields Map<String, DocumentField>
     * @param key    取值属性
     * @return
     */
    private String fields(Map<String, Object> fields, String key) {
        Object object = fields.getOrDefault(key, fields.get(ElasticSearchConstants.SEARCH_NULL));
        return object == null ? "" : object.toString();
    }

    /**
     * 构造高亮文本结果
     *
     * @param highlightFields 高亮处理类
     * @param key             取值属性
     * @return
     */
    private String highlightField(Map<String, HighlightField> highlightFields, String key) {
        String result = "";
        HighlightField highlightFieldTitle = highlightFields.get(key);
        if (highlightFieldTitle != null) {
            Text[] fragments = highlightFieldTitle.fragments();
            String lightTitle = "";
            for (Text fragment : fragments) {
                lightTitle += fragment;
            }
            result = lightTitle;
        }
        return result;
    }


    /**
     * 初始化数据
     *
     * @param category 类型
     * @return
     */
    public JsonResult initIndex(String category, Integer limit) throws IOException {
        TimeInterval timer = DateUtil.timer();
        // 开始时间
        long startLong = System.currentTimeMillis();
        if (StrUtil.isBlank(category) || ElasticSearchConstants.INFORMATION_RECRUIT.equals(category)) {
            QueryWrapper<Recruit> qr = new QueryWrapper<>();
            qr.eq("state", CheckRecordConstants.CHECK_SUCCESS).eq("invalid", 0);
            int total = recruitMapper.selectCount(qr);
            log.info("recruit : {}", total);
            // 有数据删除
            if (isExistData(ElasticSearchConstants.INFORMATION_RECRUIT)) {
                delete(ElasticSearchConstants.INFORMATION_RECRUIT);
            }
            int size = total / limit;
            if (total % limit != 0) {
                size++;
            }
            long tempEnd = System.currentTimeMillis();
            int tempLimit = limit;
            for (int k = 0; k < size; k++) {
                int number = k * tempLimit;

                if (k == size - 1) {
                    tempLimit = total - number;
                }
                List<Recruit> recruits = recruitMapper.initIndex(number, tempLimit);
                saveRecruitList(recruits);
                long temp = System.currentTimeMillis();
                log.info("recruit 第 {} 个 耗时 {} 秒 ", k, (temp - tempEnd) / 1000);
            }
        }

        if (StrUtil.isBlank(category) || ElasticSearchConstants.INFORMATION_PREACH.equals(category)) {
            QueryWrapper<Preach> qr = new QueryWrapper<>();
            qr.eq("state", CheckRecordConstants.CHECK_SUCCESS).eq("invalid", 0);
            int total = preachMapper.selectCount(qr);
            log.info("preaches : {}", total);
            if (isExistData(ElasticSearchConstants.INFORMATION_PREACH)) {
                delete(ElasticSearchConstants.INFORMATION_PREACH);
            }
            int size = total / limit;
            if (total % limit != 0) {
                size++;
            }
            long tempEnd = System.currentTimeMillis();
            int tempLimit = limit;
            for (int k = 0; k < size; k++) {
                int number = k * tempLimit;
                if (k == size - 1) {
                    tempLimit = total - number;
                }
                List<Preach> preaches = preachMapper.initIndex(number, tempLimit);
                savePreachList(preaches);
                long temp = System.currentTimeMillis();
                log.info("Preach 第 {} 个 耗时 {} 秒 ", k, (temp - tempEnd) / 1000);
            }
        }

        if (StrUtil.isBlank(category) || ElasticSearchConstants.INFORMATION_PREACH_CLOUD.equals(category)) {
            QueryWrapper<PreachCloud> qr = new QueryWrapper<>();
            qr.eq("state", CheckRecordConstants.CHECK_SUCCESS).eq("invalid", 0);
            int total = preachCloudMapper.selectCount(qr);
            log.info("PreachCloud : {}", total);
            if (isExistData(ElasticSearchConstants.INFORMATION_PREACH_CLOUD)) {
                delete(ElasticSearchConstants.INFORMATION_PREACH_CLOUD);
            }
            int size = total / limit;
            if (total % limit != 0) {
                size++;
            }
            long tempEnd = System.currentTimeMillis();
            int tempLimit = limit;
            for (int k = 0; k < size; k++) {
                int number = k * limit;
                if (k == size - 1) {
                    tempLimit = total - number;
                }
                List<PreachCloud> preachClouds = preachCloudMapper.initIndex(number, tempLimit);
                savePreachCloudList(preachClouds);
                long temp = System.currentTimeMillis();
                log.info("PreachCloud 第 {} 个 耗时 {} 秒 ", k, (temp - tempEnd) / 1000);
            }
            log.info("preachClouds over");
        }

        if (StrUtil.isBlank(category) || ElasticSearchConstants.INFORMATION_MUTUAL.equals(category)) {
            QueryWrapper<Mutual> qr = new QueryWrapper<>();
            int total = mutualMapper.selectCount(qr);
            log.info("mutual : {}", total);
            if (isExistData(ElasticSearchConstants.INFORMATION_MUTUAL)) {
                delete(ElasticSearchConstants.INFORMATION_MUTUAL);
            }
            int size = total / limit;
            if (total % limit != 0) {
                size++;
            }
            long tempEnd = System.currentTimeMillis();
            int tempLimit = limit;
            for (int k = 0; k < size; k++) {
                int number = k * limit;
                if (k == size - 1) {
                    tempLimit = total - number;
                }
                List<Mutual> mutuals = mutualMapper.initIndex(number, tempLimit);
                saveMutualList(mutuals);
                long temp = System.currentTimeMillis();
                log.info("articles 第 {} 个 耗时 {} 秒 ", k, (temp - tempEnd) / 1000);
            }
            log.info("mutuals over");
        }

        if (StrUtil.isBlank(category) || ElasticSearchConstants.INFORMATION_ARTICLE.equals(category)) {
            int total = articleMapper.selectCount(new QueryWrapper<>());
            log.info("article : {}", total);
            if (isExistData(ElasticSearchConstants.INFORMATION_ARTICLE)) {
                delete(ElasticSearchConstants.INFORMATION_ARTICLE);
            }
            int size = total / limit;
            if (total % limit != 0) {
                size++;
            }
            long tempEnd = System.currentTimeMillis();
            int tempLimit = limit;
            for (int k = 0; k < size; k++) {
                int number = k * limit;
                if (k == size - 1) {
                    tempLimit = total - number;
                }
                List<Article> articles = articleMapper.initIndex(number, tempLimit);
                saveArticleList(articles);
                long temp = System.currentTimeMillis();
                log.info("articles 第 {} 个 耗时 {} 秒 ", k, (temp - tempEnd) / 1000);
            }
            log.info("articles over");
        }

        if (StrUtil.isBlank(category) || ElasticSearchConstants.INFORMATION_OFFICIAL.equals(category)) {
            int total = officialMapper.selectCount(new QueryWrapper<>());
            log.info("official : {}", total);
            if (isExistData(ElasticSearchConstants.INFORMATION_OFFICIAL)) {
                delete(ElasticSearchConstants.INFORMATION_OFFICIAL);
            }
            int size = total / limit;
            if (total % limit != 0) {
                size++;
            }
            long tempEnd = System.currentTimeMillis();
            int tempLimit = limit;
            for (int k = 0; k < size; k++) {
                int number = k * limit;
                if (k == size - 1) {
                    tempLimit = total - number;
                }
                List<Official> officials = officialMapper.initIndex(number, tempLimit);
                saveOfficialList(officials);
                long temp = System.currentTimeMillis();
                log.info("officials 第 {} 个 耗时 {} 秒 ", k, (temp - tempEnd) / 1000);
            }
            log.info("officials over");
        }

        if (ElasticSearchConstants.INFORMATION_PUSH_MSG.equals(category)) {
            int total = pushMsgMapper.selectCount(new QueryWrapper<>());
            int size = total / limit;
            if (total % limit != 0) {
                size++;
            }
            long tempEnd = System.currentTimeMillis();
            for (int k = 0; k < size; k++) {
                int number = k * limit;
                if (k == size - 1) {
                    limit = total - number;
                }
                List<PushMsg> pushMsgs = pushMsgMapper.initIndex(number, limit);
                save(pushMsgs);
                long temp = System.currentTimeMillis();
                log.info("pushMsg 第 {} 个 耗时 {} 秒 ", k, (temp - tempEnd) / 1000);
            }

        }
        // 结束时间
        long endLong = System.currentTimeMillis();
        log.info("完成时间 : {} 分", (endLong - startLong) / 1000 / 60);

        return JsonResult.ok("耗时：" + timer.intervalMinute() + "分钟");
    }

    /**
     * 根据学生查询明天举办的校内宣讲会、空中宣讲会
     *
     * @param studentId 学生ID
     * @param date      日期
     * @return
     */
    public JsonResult searchTomorrowPreach(Integer studentId, String date) throws IOException {
        // 搜索的索引
        SearchRequest index = new SearchRequest(ElasticSearchConstants.INDEX_NAME_PUSH_MSG);
        // 构建搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 构建排序
        searchSourceBuilder.sort(new FieldSortBuilder("businessDate").order(SortOrder.ASC));
        // 复合查询 should或者 must并且
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        // 单位同意推送
        boolQueryBuilder.must(QueryBuilders.termQuery("companyFlag", PushConstants.YES));
        // 学校同意
        boolQueryBuilder.must(QueryBuilders.termQuery("adminFlag", PushConstants.YES));
        // 学生ID
        boolQueryBuilder.must(QueryBuilders.termQuery("studentId", studentId));
        // 宣讲会、空中宣讲会
        boolQueryBuilder
                .should(QueryBuilders.termQuery("type.keyword", ElasticSearchConstants.INFORMATION_PREACH))
                .should(QueryBuilders.termQuery("type.keyword", ElasticSearchConstants.INFORMATION_PREACH_CLOUD));
        // 日期范围
        Date dateTime = DateUtil.parseDate(date);
        Date startDate = DateUtil.beginOfDay(dateTime);
        Date endDate = DateUtil.endOfDay(dateTime);
        boolQueryBuilder.must(QueryBuilders.rangeQuery("businessDate").gte(startDate.getTime()).lte(endDate.getTime()));
        // 设置为true就会返回真实的命中条数
        searchSourceBuilder.trackTotalHits(true);
        searchSourceBuilder.query(boolQueryBuilder);
        // source builder 10秒timeout
        searchSourceBuilder.timeout(new TimeValue(10, TimeUnit.SECONDS));
        index.source(searchSourceBuilder);
        // 请求查询得到返回响应
        SearchResponse searchResponse = restHighLevelClient.search(index, RequestOptions.DEFAULT);

        List<PubliclyCareerVO> preachList = new ArrayList<>();
        List<PubliclyCareerVO> preachCloudList = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, Object> fields = hit.getSourceAsMap();
            PubliclyCareerVO item = new PubliclyCareerVO();
            item.setId(fields.get("businessId") != null ? (Integer) fields.get("businessId") : null);
            item.setPushMsgId(fields.get("id") != null ? Integer.parseInt(fields.get("id").toString()) : null);
            item.setTitle(fields.get("title") != null ? fields.get("title").toString() : "");
            item.setType(fields.get("type") != null ? fields.get("type").toString() : "");
            item.setMatching(fields.get("matching") != null ? fields.get("matching").toString() : "");

            long l = fields.get("businessDate") != null ? (Long)fields.get("businessDate") : 0L;
            if (l != 0L) {
                item.setHoldTime(DateUtil.date(l));
                item.setTimeState(DateUtil.date().getTime() < item.getHoldTime().getTime() ? 0 : 1);

                if (ElasticSearchConstants.INFORMATION_PREACH.equals(item.getType())) {
                    preachList.add(item);
                }
                if (ElasticSearchConstants.INFORMATION_PREACH_CLOUD.equals(item.getType())) {
                    preachCloudList.add(item);
                }
            }
        }

        return JsonResult.ok().put("preachList", preachList).put("preachCloudList", preachCloudList);
    }


    public PageResult<StudentPushMsgVO> listPushMsg(StudentPushMsgVO params, int page, int limit) throws IOException {
        page = page <= 1 ? 1 : page;

        SearchRequest index = new SearchRequest(ElasticSearchConstants.INDEX_NAME_PUSH_MSG);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 设置为true就会返回真实的命中条数
        searchSourceBuilder.trackTotalHits(true);
        // 构建分页
        searchSourceBuilder.size(3000);
        // 构建排序
        searchSourceBuilder.sort(new FieldSortBuilder("pushDate").order(SortOrder.DESC));

        // 复合查询 should或者 must并且
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        // 单位同意推送
        boolQueryBuilder.must(QueryBuilders.termQuery("companyFlag", PushConstants.YES));
        // 学校同意
        boolQueryBuilder.must(QueryBuilders.termQuery("adminFlag", PushConstants.YES));

        boolQueryBuilder.must(QueryBuilders.termQuery("yearId", params.getYearId()));

        if (!StrUtil.isBlank(params.getType())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("type", params.getType()));
        }
        if (!StrUtil.isBlank(params.getReadFlag())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("readFlag", params.getReadFlag()));
        }
        if (!StrUtil.isBlank(params.getResumeFlag())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("resumeFlag", params.getResumeFlag()));
        }
        if (!StrUtil.isBlank(params.getCollegeName())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("collegeName.keyword", params.getCollegeName()));
        }
        if (!StrUtil.isBlank(params.getMajorName())) {
            String[] majors = params.getMajorName().split("\\(");
            boolQueryBuilder.must(QueryBuilders.termQuery("majorName.keyword", majors[0]));
        }
        if (!StrUtil.isBlank(params.getXh())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("xh.keyword", params.getXh()));
        }
        if (!StrUtil.isBlank(params.getTitle())) {
            boolQueryBuilder.must(QueryBuilders.wildcardQuery("title.keyword", "*" + params.getTitle() + "*"));
        }

        String startTime = params.getStartTime();
        String endTime = params.getEndTime();
        if (!StrUtil.isBlank(startTime) && !StrUtil.isBlank(endTime)) {
            startTime += " 00:00:00.000";
            endTime += " 23:59:59.000";

            DateTime startDate = DateUtil.parse(startTime);
            DateTime endDate = DateUtil.parse(endTime);

            boolQueryBuilder.must(QueryBuilders.rangeQuery("pushDate").from(startDate.getTime()).to(endDate.getTime()));
        }


        searchSourceBuilder.query(boolQueryBuilder);

        // source builder 10秒timeout
        searchSourceBuilder.timeout(new TimeValue(10, TimeUnit.SECONDS));
        index.source(searchSourceBuilder);

        // 请求查询得到返回响应
        SearchResponse searchResponse = restHighLevelClient.search(index, RequestOptions.DEFAULT);

        // 数据条数
        long total = searchResponse.getHits().getTotalHits().value;

        int pageIndex = 0;
        List<String> xhs = new ArrayList<>();
        List<Integer> companyIds = new ArrayList<>();
        Map<Object, Object> dictMaps = dictService.getCacheDictMaps();
        List<StudentPushMsgVO> list = new ArrayList<>();
        int id = 0;
        for (SearchHit hit : searchResponse.getHits().getHits()) {

            int start = (page - 1) * limit;
            if (pageIndex < start) {
                pageIndex++;
                continue;
            }
            if (pageIndex == start + limit) {
                break;
            }

            Map<String, Object> fields = hit.getSourceAsMap();

            StudentPushMsgVO item = new StudentPushMsgVO();

            item.setId(id++);
            item.setYearId(fields.get("yearId") != null ? fields.get("yearId").toString() : "");
            item.setType(fields.get("type") != null ? fields.get("type").toString() : "");

            String xh = fields.get("xh") != null ? fields.get("xh").toString() : "";
            item.setXh(xh);
            xhs.add(xh);

            item.setXm("");
            item.setCollegeName(fields.get("collegeName") != null ? fields.get("collegeName").toString() : "");
            item.setMajorName(fields.get("majorName") != null ? fields.get("majorName").toString() : "");

            Integer companyId = fields.get("companyId") != null ? (Integer) fields.get("companyId") : null;
            item.setCompanyId(companyId);
            item.setCompanyName("");
            item.setCompanyUrl("/home/companydetail?id=" + companyId);
            companyIds.add(companyId);

            String nature = fields.get("nature") != null ? fields.get("nature").toString() : "";
            if (!StrUtil.isBlank(nature)) {
                item.setCompanyNature(dictService.cacheLabel(DictConstants.COMPANY_NATURE, nature, dictMaps));
            }

            String industry = fields.get("industry") != null ? fields.get("industry").toString() : "";
            if (!StrUtil.isBlank(industry)) {
                item.setCompanyIndustry(dictService.cacheLabel(DictConstants.COMPANY_INDUSTRY, industry, dictMaps));
            }

            String scale = fields.get("scale") != null ? fields.get("scale").toString() : "";
            if (!StrUtil.isBlank(scale)) {
                item.setCompanyScale(dictService.cacheLabel(DictConstants.COMPANY_SCALE, scale, dictMaps));
            }

            String province = fields.get("province") != null ? fields.get("province").toString() : "";
            String city = fields.get("city") != null ? fields.get("city").toString() : "";
            item.setProvinceCity(province + city);

            item.setBusinessId(fields.get("businessId") != null ? fields.get("businessId").toString() : "");
            item.setTitle(fields.get("title") != null ? fields.get("title").toString() : "");

            item.setReadFlag(fields.get("readFlag") != null ? fields.get("readFlag").toString() : "");
            item.setResumeFlag(fields.get("resumeFlag") != null ? fields.get("resumeFlag").toString() : "");

            long pushDateL = fields.get("pushDate") != null ? (Long) fields.get("pushDate") : 0L;
            if (pushDateL != 0L) {
                item.setPushDate(DateUtil.date(pushDateL));
            }

            String positionResult = "";
            String positionMatching = fields.get("positionMatching") != null ? fields.get("positionMatching").toString() : "";
            String positionNames = fields.get("positionNames") != null ? fields.get("positionNames").toString() : "";
            if (!StrUtil.isBlank(positionMatching) && !StrUtil.isBlank(positionNames)) {
                String[] pms = positionMatching.split("\\|");
                String[] pns = positionNames.split(",");
                if (pms.length == pns.length) {
                    for (int i = 0; i < pms.length; i++) {
                        String[] matching = pms[i].split(",");
                        positionResult += i + 1 + "." + pns[i] + "[" + matching[1] + "]";
                        positionResult += "<br>";
                    }
                } else {
                    String[] matching = pms[0].split(",");
                    positionResult = "1." + pns[0] + "[" + matching[1] + "]";
                }
            }
            item.setPositionResult(positionResult);

            String businessUrl = "";
            switch (item.getType()) {
                case "1":
                    businessUrl = "/home/career/internship?id=" + item.getBusinessId();
                    break;
                case "2":
                    businessUrl = "/home/career/preachmore?id=" + item.getBusinessId();
                    break;
                case "3":
                    businessUrl = "/home/career/cloudmore?id=" + item.getBusinessId();
                    break;
            }
            item.setBusinessUrl(businessUrl);

            list.add(item);
            pageIndex++;
        }

        if (list.size() == 0) {
            return new PageResult<>(list, total);
        }

        List<Company> companyList = companyService.list(new QueryWrapper<Company>().in("id", companyIds));
        List<Student> studentList = studentMapper.selectList(new QueryWrapper<Student>().select("xh, xm").in("xh", xhs));

        for (StudentPushMsgVO item : list) {
            for (Student student : studentList) {
                if (item.getXh().equals(student.getXh())) {
                    item.setXm(student.getXm());
                    break;
                }
            }

            for (Company company : companyList) {
                if (item.getCompanyId().equals(company.getId())) {
                    item.setCompanyName(company.getName());
                    break;
                }
            }
        }

        return new PageResult<>(list, total);
    }

}
